﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;

namespace PayloadTracker.APRS
{
    /// <summary>
    /// Generic serial modem provider for APRS.
    /// </summary>
    [Serializable] 
    [SetupControlAttribute(typeof(GenericSerialModemSetup))] //bind this class to GenericSerialModemSetup dialog for the setup menu.
    public class GenericSerialModem : IAPRSProvider
    {
        [Serializable]
        public struct SerialPortConfiguration
        {
            public string Port;
            public int BaudRate;
            public Parity Parity;
            public int DataBits;
            public StopBits stopBits;

        }
        [Serializable]
        public struct APRSSerialModemConfiguration
        {
            public SerialPortConfiguration SerialConfiguration;
            public string InitilizationData;
            public string NewLineDeliminator;
            //public APRS.Parsers.IParser Parser;
        }

        SerialPort m_Port;
        APRSSerialModemConfiguration m_Config;
        bool m_Enabled;
        bool m_Initialized = false;


        public GenericSerialModem(APRSSerialModemConfiguration config)
            : base("Generic Serial Modem")
        {

            Initialize(config);

        }


        /// <summary>
        /// private constructor used for serialization and configuration. DO NOT USE.
        /// </summary>
        private GenericSerialModem()
            : base("Generic Serial Modem")
        {

        }

        private void Initialize(APRSSerialModemConfiguration config)
        {
            m_Config = config;
            m_Enabled = false;
            m_Port = new SerialPort(
                config.SerialConfiguration.Port,
                config.SerialConfiguration.BaudRate,
                config.SerialConfiguration.Parity,
                config.SerialConfiguration.DataBits,
                config.SerialConfiguration.stopBits);


            if (config.NewLineDeliminator.Length > 0)
                m_Port.NewLine = config.NewLineDeliminator;
        }
        public override void Start()
        {
            if (!m_Port.IsOpen)
            {
                try
                {
                    m_Port.Open();
                }
                catch (System.InvalidOperationException ex)
                {
                    Logger.LOG.Error("Can't open port: " + m_Port.PortName + ". " + ex.Message.ToString(), false);
                }
                catch (System.IO.IOException ex)
                {
                    Logger.LOG.Error("Can't open port: " + m_Port.PortName + ". " + ex.Message.ToString(), false);
                }
            }

            if (m_Config.InitilizationData.Length > 0)
                m_Port.WriteLine(m_Config.InitilizationData);

            m_Enabled = true;
        }

        public override void Stop()
        {
         
            m_Port.Close();
            m_Enabled = false;
        }

        public override void Tick()
        {
            if(m_Enabled)
            {
                if (!m_Port.IsOpen)
                    throw new Exception("Port error: serial port no longer open.");

                if(m_Port.BytesToRead > 0)
                {
                    string data = m_Port.ReadLine().Trim();



                    APRSBeacon parsed = null;
                    Logger.LOG.WriteLine("Parsing APRS String: " + data);
                    try
                    {
                        parsed = APRS.Parsers.ParserProvider.Instance.AutoParse(data);
                    }
                    catch (Exception)
                    {
                    }

                    if (parsed != null)
                        OnAprsUpdate(parsed);
                    else
                        Logger.LOG.WriteLine("Invalid Sentence: " + data);
                        
                    
                    
                    //var parser = APRS.Parsers.ParserProvider.Instance.GetParser(data);
                    //if (parser != null)
                    //{
                    //    Logger.LOG.WriteLine("Parsing APRS String: " + data);
                    //    var packet = parser.Parse(data);
                    //    if(packet != null)
                    //        OnAprsUpdate(packet);
                    //}
                    //else
                    //    Logger.LOG.Error("Invalid Sentence: " + data);
                }

            }
            else if (m_Port.IsOpen)
            {
                m_Port.ReadExisting();
            }
        }

        public override void ReadXml(System.Xml.XmlReader reader)
        {
            var s = new System.Xml.Serialization.XmlSerializer(typeof(APRSSerialModemConfiguration));
            APRSSerialModemConfiguration config = ((APRSSerialModemConfiguration)s.Deserialize(reader));
            Initialize(config);
        }

        public override void WriteXml(System.Xml.XmlWriter writer)
        {
            var s = new System.Xml.Serialization.XmlSerializer(typeof(APRSSerialModemConfiguration));
            s.Serialize(writer, m_Config);
        }
    }
}
